home *** CD-ROM | disk | FTP | other *** search
- /*******************************
- Halftoning Sample Code:
-
- D. Lipton
-
- ********************************/
-
- #ifndef THINK_C
- #include <QuickDraw.h>
- #include <QDOffscreen.h>
- #include <Events.h>
- #include <FixMath.h>
- #endif
-
-
- /*****************
- Define target resolution value:
- Note, if less than 72, source scaling
- code does not work. It assumes target
- resolution is always >= 72 so pointer
- arithmetic in source image doesn't need
- to do a multiply every time. This could
- be fixed at the expense of performance
- ******************/
- #define RES 72
-
- /*************
- Routine returns luminance for a pixel.
-
- pPixel points to the pixel in the PixMap.
- pMap is the Pixmaps PixMapPtr.
-
- Non optimal for 8 bit.
- Should cache luminances for CLUT and read them back
- rather than calculating for every pixel.
- Left as an exercise for the reader.
-
- **************/
-
- long LUMVAL(Ptr pPixel, PixMapPtr pMap)
- {
- long red, green, blue;
-
- if (pMap->pixelSize == 32) {
-
- red = (long)(unsigned char)*(++pPixel); /* Skip alpha, get red */
- green = (long)(unsigned char)*(++pPixel); /* Get green */
- blue = (long)(unsigned char)*(++pPixel); /* Get blue */
-
- return( (30 * red + 59 * green + 11 * blue)/100);
-
- } else if (pMap->pixelSize == 8) {
-
- RGBColor* theColor;
- theColor = &((*(pMap->pmTable))->ctTable[ (unsigned char)*pPixel ].rgb);
-
- return( (30 * (theColor->red >> 8) + 59 * (theColor->green >> 8) + 11 * (theColor->blue >> 8))/100);
-
- } /* end if */
-
- } /* LUMVAL */
-
-
-
-
-
- /*******************************
- Routine: HalftonePixMap:
-
- Routine takes a pixmap and halftones it
- into a 300dpi 1 bit gworld.
-
- The halftoned image is returned in a picture handle.
-
- ********************************/
- PicHandle HalftonePixMap(PixMapHandle hSource, Boolean qdPixMap,
- short Resolution)
- {
- short width300, height300;
- /* 300-dpi width and height. */
- Fixed scale;
- Rect bounds300;
- QDErr status;
- GWorldPtr theGworld;
- PixMapHandle offScreen;
- Fixed sourceX, sourceY;
- short lastX, lastY;
- short destX, destY;
- Ptr pRaster, pPixel, pDestRaster;
- long *nextDestLong;
- long luminance;
- register unsigned long mask, destLong;
- PicHandle aPic;
- PixMap *pSource;
- long matrix[8][8] = { 7, 111, 183, 239, 231, 191, 71, 15,
- 87, 47, 135, 175, 199, 159, 55, 127,
- 215, 143, 39, 79, 119, 63, 151, 207,
- 247, 223, 103, 31, 23, 95, 167, 255 ,
- 231, 191, 71, 15, 7, 111, 183, 239 ,
- 199, 159, 55, 127, 87, 47, 135, 175,
- 119, 63, 151, 207, 215, 143, 39, 79,
- 23, 95, 167, 255, 247, 223, 103, 31
- };
-
- long *pMatrix, *pMatrixRow;
- long M = 8;
- long N = 8;
- long I, J;
- /* Matrix coordinates. */
-
- if(Resolution == 0)
- Resolution = 72;
-
- if(Resolution < 72)
- return(0);
-
- HLock(hSource);
- if(qdPixMap)
- LockPixels(hSource);
-
- pSource = *hSource;
-
- scale = FixRatio(Resolution, 72);
-
- /* Compute width and height at new resolution. */
-
- width300 = FixMul(scale, (long)(pSource->bounds.right -
- pSource->bounds.left) << 16) >> 16;
- height300 = FixMul(scale, (long)(pSource->bounds.bottom -
- pSource->bounds.top) << 16) >> 16;
-
-
- bounds300.top = pSource->bounds.top;
- bounds300.bottom = bounds300.top + height300;
- bounds300.left = pSource->bounds.left;
- bounds300.right = bounds300.left + width300;
-
-
- /* Allocate a 1-bit GWorld to draw into. */
-
- status = NewGWorld(&theGworld, 1, &bounds300, nil, nil, 0);
- if (status)
- return nil;
-
-
- offScreen = GetGWorldPixMap(theGworld); /* 7.0 only */
- LockPixels(offScreen);
-
- /* Compute scale for walking source pixels. */
- scale = FixRatio(72, Resolution);
-
- /* Source X, Y will walk source image in fixed-point numbers.
- Integer part will be saved to see when we've crossed into
- a new pixel boundary for updating pointers and luminance
- value. */
-
- sourceY = pSource->bounds.top << 16;
- lastY = sourceY >> 16;
-
- /* Initialize raster pointers. */
- if( qdPixMap )
- pRaster = GetPixBaseAddr(hSource);
- else
- pRaster = pSource->baseAddr;
-
- pDestRaster = GetPixBaseAddr(offScreen);
-
- I = 0; /* Y index into dither matrix. */
- pMatrixRow = &(matrix[0][0]); /* Point to next row of matrix. */
-
- for (destY = 0; destY < height300; ++destY) {
-
- pPixel = pRaster;
- luminance = LUMVAL(pPixel, pSource);
- mask = 0x80000000;
- destLong = 0;
- nextDestLong = (long*)pDestRaster;
-
- sourceX = pSource->bounds.left << 16;
- lastX = sourceX >> 16;
-
- J = 0; /* X index into dither matrix. */
- pMatrix = pMatrixRow; /* Point into current row of
- dither matrix. */
-
- for (destX = 0; destX < width300; ++destX) {
-
- /* If the luminance for this pixel is less than matrix
- value, turn on the pixel. */
-
- if (luminance < *pMatrix)
- destLong |= mask;
-
- /* Adjust masks and longs for next device pixel.
- Pixels are set in a long-word register. When all
- 32 bits in the register have been set, the register
- is layed into the pixMap. */
-
- mask >>= 1;
- if (mask == 0) { /* We've done 32 pixels, lay in
- the long word into the
- offscreen. */
- mask = 0x80000000; /* Reset the mask. */
- *(nextDestLong++) = destLong;
- destLong = 0;
- } /* End if */
-
-
- /* Update pointer into dither matrix:
- Instead of using matrix[X % M, Y % N],
- we use a pointer and counters. Mod function
- combined with an array index calculation would
- be more time-consuming. */
-
- ++pMatrix; /* Next element in row. */
- if (++J >= N) { /* Get J+1 mod N, faster than
- doing real mod every pixel. */
-
- J = 0;
- pMatrix = pMatrixRow; /* Start at beginning of matrix
- row again. */
-
- } /* End if */
-
-
- sourceX += scale; /* Add fixed scale increment to
- source X value. */
-
- /* Check to see if we crossed into next source pixel.
- Note: Getting integer portion can be done faster than
- a shift; this is left as an exercise for the reader. */
- if ((sourceX >> 16) > lastX) {
-
- lastX = sourceX >> 16;
- /* Get new integer portion of X coordinate. */
- if (pSource->pixelSize == 8)
- /* Point to next 8-bit pixel. */
- ++pPixel;
- else if (pSource->pixelSize == 32)
- /* Point to next 32-bit pixel. */
- pPixel += 4;
-
- luminance = LUMVAL(pPixel, pSource);
- /* Get luminance for next pixel. */
-
- } /* End if */
-
-
- } /* End for */
-
- /* Make sure the last long-word was laid into the target
- image. If 1 in the mask is not all the way left, it means
- there are pixels in the next long, but not enough to force
- the write within the raster loop, so lay it into the
- block. */
- if (mask != 0x80000000)
- *nextDestLong = destLong;
-
- pDestRaster += ((*offScreen)->rowBytes & 0x3fff);
- /* Get into next destination raster. */
-
- sourceY += scale;
- /* Add fixed scale increment to source Y value. */
- /* Checked to see if we crossed into next source raster. */
- if ( (sourceY >> 16) > lastY ) {
-
- lastY = sourceY >> 16;
- /* Get integer portion of Y coordinate. */
- pRaster += (pSource->rowBytes & 0x3fff);
- /* Get next source raster. */
-
- } /* End if */
-
- /* Update pointer into dither matrix. */
-
- pMatrixRow += M; /* Point to next row of matrix. */
- if (++I >= M) {
- /* Get I+1 mod M, faster than doing real mod every raster. */
-
- I = 0;
- pMatrixRow = &(matrix[0][0]);
- /* Point to next row of matrix. */
-
- } /* End if */
-
-
- } /* End for */
-
-
- /* Create the picture to return and dispose of the offscreen. */
-
- aPic = OpenPicture(&bounds300);
- HLock((Handle)offScreen);
- CopyBits((BitMap*)*offScreen, &thePort->portBits, &bounds300,
- &bounds300, 0, 0L);
- ClosePicture();
-
- DisposeGWorld(theGworld);
-
- HUnlock(hSource);
- if(qdPixMap)
- UnlockPixels(hSource);
-
- return(aPic);
-
- } /* HalftonePixMap */
-
-